<template>
  <div>
    <el-table
      border
      ref="table"
      :class="'tableID_' + tableID"
      id="el-table"
      style="width: 100%"
      v-loading="loading"
      :stripe="stripe"
      :row-key="(row) => row[rowKey]"
      :max-height="
        (height
          ? height
          : pageHidden
          ? tableHeight - otherHeight
          : tableHeight - 96) + 'px'
      "
      :data="tableData"
      :span-method="spanMethod"
      :row-class-name="tableRowClassName"
      :cell-class-name="tableCellClassName"
      :show-summary="showSummary"
      :summary-method="getSummaries"
      @row-dblclick.self="rowDblclick"
      @select="handleSelectionChange"
      @row-click="handleRowClick"
      @select-all="handleSelectionChange"
    >
      <el-table-column type="expand" v-if="expand"></el-table-column>
      <el-table-column
        v-if="selection"
        type="selection"
        width="40"
        :selectable="selectable"
        align="center"
      ></el-table-column>
      <Column
        v-for="item in tableOption"
        :key="item.prop"
        :column="item"
        :autoWidth="autoWidth"
        :editableRowIndex="editableRowIndex"
        @cellClick="cellClick"
        v-on="$listeners"
      ></Column>
    </el-table>
    <div :class="{ hidden: pageHidden }" class="pagination-container">
      <el-pagination
        :background="background"
        :current-page.sync="currentPage"
        :page-size.sync="pageSize"
        :layout="layout"
        :total="total"
        v-bind="$attrs"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>
<script>
import { scrollTo, tableScrollTo, position } from "@/utils/scroll-to";
import Column from "./components/Column.vue";
import _ from "lodash";
import { mixin } from "@/mixins/tableHeight.js";
export default {
  mixins: [mixin],
  components: { Column },
  props: {
    api: Function, // 数据接口
    renderFunc: {
      type: Function,
      default: () => {
        return () => {};
      }
    },
    autoWidth: {
      //列宽均分
      type: Boolean,
      default: false
    },
    autoPlay: {
      //是否自动请求数据（分页等）
      type: Boolean,
      default: true
    },
    immediate: {
      //是否立即执行api请求
      type: Boolean,
      default: true
    },
    tableOption: {
      // 表格列配置项
      type: Array,
      default: () => []
    },
    dataSource: {
      // 表格列配置项
      type: Array,
      default: () => [{}]
    },
    height: {
      // 表格最大高度
      type: Number,
      default: 0
    },
    otherHeight: {
      // 表格外其他元素高度
      type: Number,
      default: 0
    },
    limit: {
      // 每页条数
      type: Number,
      default: 10
    },
    totalCount: {
      // 数据总数
      type: Number,
      default: 0
    },

    pageSizes: {
      // 每页条数集合
      type: Array,
      default() {
        return [10, 20, 30, 50];
      }
    },
    layout: {
      // 分页功能参数
      type: String,
      default: "total, prev, pager, next, jumper"
    },
    background: {
      // 分页选中背景色
      type: Boolean,
      default: true
    },
    autoScroll: {
      // 翻页列表是否回到顶部
      type: Boolean,
      default: true
    },
    pageHidden: {
      // 是否隐藏分页
      type: Boolean,
      default: false
    },
    pageNo: {
      // 当前页码
      type: Number,
      default: 1
    },
    queryParams: {
      // 数据接口参数
      type: Object,
      default: () => {}
    },
    selection: {
      // 表格多选
      type: Boolean,
      default: false
    },

    disabledSelectionRows: {
      // 表格多选禁用关键字集合
      type: Array,
      default() {
        return [];
      }
    },
    expand: {
      // 是否支持展开
      type: Boolean,
      default: false
    },
    isMerge: {
      // 是否合并单元格
      type: Boolean,
      default: false
    },
    mergeColumn: {
      // 表格合并得列对应得字段集合
      type: Array,
      default() {
        return [];
      }
    },
    datumKey: {
      // 表格合并得基准列
      type: String,
      default: ""
    },
    rowKey: {
      // 行数据的 Key
      type: String,
      default: ""
    },
    selectionRows: {
      // 默认选中数据
      type: Array,
      default() {
        return [];
      }
    },
    showSummary: {
      // 是否合显示合计
      type: Boolean,
      default: false
    },
    summaryOption: {
      // 合计行配置
      type: Object,
      default: () => {
        return {
          summary: false,
          unit: "",
          label: "合计",
          emptyText: "N/A",
          summaryOptionArr: false //只展示筛选字段
        };
      }
    },
    rowClassName: {
      //row className
      type: Function,
      default: () => {
        return () => {};
      }
    },
    stripe: {
      //斑马纹
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      tableID: new Date().getTime(),
      loading: false,
      tableData: [],
      total: 0,
      spanArr: [],
      editableRowIndex: null,
      selectionData: []
    };
  },
  computed: {
    pageSize: {
      get() {
        return this.limit;
      },
      set(val) {
        this.$emit("update:limit", val);
      }
    },
    currentPage: {
      get() {
        return this.pageNo;
      },
      set(val) {
        this.$emit("update:pageNo", val);
      }
    }
  },
  watch: {
    pageNo: {
      deep: true,
      handler: function() {
        if (this.autoScroll) {
          this.getData();
        }
      },
    },
    limit: {
      deep: true,
      handler: function() {
        if (this.autoScroll) {
          this.getData();
        }
      }
    },
    queryParams: {
      deep: true,
      handler: function() {
        if (this.autoScroll) {
          this.getData();
        }
      }
    },
    dataSource: {
      deep: true,
      handler: function() {
        if (!this.api) {
          this.tableData = this.dataSource || [];
        }
      },
      deep: true,
      immediate: true
    },
    tableData: {
      deep: true,
      handler: function() {
        if (this.tableData.length === 0) {
          this.$nextTick(() => {
            const tableEmptyDom = document.querySelector(
              `.tableID_${this.tableID}`
            );
            if (tableEmptyDom) {
              tableEmptyDom.style.position = "relative";
              const bodyWrapper = document.querySelector(
                `.tableID_${this.tableID} .el-table__body-wrapper`
              );
              let emptyTextDom = document.querySelector(
                `.tableID_${this.tableID} #el-table__empty-text_custom`
              );
              if (!emptyTextDom) {
                emptyTextDom = document.createElement("div");
                emptyTextDom.className = "el-table__empty-text_custom";
                emptyTextDom.id = "el-table__empty-text_custom";
                emptyTextDom.innerText = "暂无数据";
                tableEmptyDom.appendChild(emptyTextDom);
              }
            }
          });
        } else {
          const emptyTextDom = document.querySelector(
            `.tableID_${this.tableID} #el-table__empty-text_custom`
          );
          if (emptyTextDom) {
            emptyTextDom.remove();
          }
        }
      },
      immediate: true
    },
    selectionRows: {
      deep: true,
      handler: function() {}
    }
  },
  mounted() {
    if (this.immediate) {
      this.getData();
    }
  },
  methods: {
    async getData() {
      this.loading = true;
      if (this.api) {
        let applyData = {
          ...this.queryParams
        };
        if (!this.pageHidden) {
          applyData = {
            pageSize: this.pageSize,
            pageNum: this.currentPage,
            ...applyData
          };
        }
        const res = await this.api({ ...applyData });
        this.loading = false;
        if (this.autoPlay) {
          if (res.code === 'SUCCESS' && res.data) {
            this.tableData = res.data;
            this.total = res.total;
          }
        } else {
          const result = this.renderFunc(res);
          this.tableData = result.data;
          this.total = result.total;
        }
      } else {
        this.tableData = this.dataSource;
      }
      this.$emit("update:totalCount", this.total);
      this.clearSelection();

      this.loading = false;
      if (this.isMerge) {
        this.spanArr = this.mergeTableRowSpan(this.mergeColumn, this.datumKey);
      }
      scrollTo(0, 0);
      tableScrollTo(this.$refs.table, 0);
      setTimeout(() => {
        this.toggleSelection(this.selectionRows);
      }, 100);
    },
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = this.summaryOption.label;
          return;
        }
        if (
          this.summaryOption.summaryOptionArr &&
          !Object.keys(this.summaryOption.summaryOptionArr).includes(
            column.property
          )
        )
          return;
        const values = data.map(item => Number(item[column.property]));
        if (!values.every(value => isNaN(value))) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr);
            if (!isNaN(value)) {
              return Number(prev) + value;
              // return Number(prev).tranAdd(curr);
            } else {
              return prev;
            }
          }, 0);
          sums[index] = this.$utils.changeDecimal(
            sums[index],
            this.summaryOption.summaryOptionArr[column.property]
          );
          sums[index] += ` ${this.summaryOption.unit || ""}`;
        } else {
          sums[index] = this.summaryOption.emptyText;
        }
      });

      return sums;
    },

    selectable(row) {
      return !this.disabledSelectionRows.includes(row[this.rowKey]);
    },

    handleSelectionChange(val, aaa) {
      if (val.length === 0) {
        const curPageRowKeys = this.tableData.map(item => item[this.rowKey]);
        const selectionRows = this.selectionRows.filter(
          item => !curPageRowKeys.includes(item[this.rowKey])
        );
        this.$emit("update:selectionRows", selectionRows);
        this.$emit("dddd", selectionRows);
      } else {
        const curPageRowKeys = this.tableData.map(item => item[this.rowKey]);
        let selectionRows = this.selectionRows.filter(
          item => !curPageRowKeys.includes(item[this.rowKey])
        );
        selectionRows = selectionRows.concat(...val);
        this.$emit("update:selectionRows", selectionRows);
        this.$emit("dddd", selectionRows);
      }
    },
    handleRowClick(row, column, event) {
      this.$emit("row-click", { row, column, event });
    },
    toggleSelection(rows) {
      // rows.forEach(row => {
      //   this.$refs.table.toggleRowSelection(row);
      // });
      const rowKys = rows.map(item => item[this.rowKey]);
      const flagArr = this.tableData.filter(item =>
        rowKys.includes(item[this.rowKey])
      );
      if (flagArr && flagArr.length > 0) {
        flagArr.forEach(row => {
          this.$refs.table.toggleRowSelection(row);
        });
      } else {
        this.clearSelection();
      }
    },
    clearSelection() {
      this.$refs.table && this.$refs.table.clearSelection();
    },
    rowDblclick(row, column, event) {
      this.editableRowIndex = row.rowIndex;
    },
    cellClick(row, column, event) {
      this.editableRowIndex = null;
    },

    refresh(pageNo) {
      pageNo && this.$emit("update:limit", pageNo);
      this.$emit("pagination", { pageNo: pageNo || 1, pageSize: 10 });
      this.getData();
    },
    clearTable() {
      this.tableData = [];
    },
    handleSizeChange(val) {
      this.$emit("update:limit", val);
      this.$emit("pagination", { pageNo: 1, limit: val });
    },
    handleCurrentChange(val) {
      this.$emit("update:pageNo", val);
      this.$emit("pagination", { pageNo: val, limit: this.pageSize });
    },
    tableRowClassName({ row, rowIndex }) {
      row.rowIndex = rowIndex;
      return this.rowClassName({ row, rowIndex });
    },
    tableCellClassName({ row, column, rowIndex, columnIndex }) {
      column.columnKey = column.property;
      column.columnLabel = column.label;
      column.columnIndex = columnIndex;
    },
    spanMethod({ row, column, rowIndex, columnIndex }) {
      if (!this.spanArr[columnIndex] || column.type !== "default") {
        return [1, 1];
      } else {
        return [this.spanArr[columnIndex][rowIndex], 1];
      }
    },
    /**
     *
     * @param {*} data tableData
     * @param {*} prop 要合并的列
     * @param {*} spanArr 返回的数组集合
     * @param {*} datumKey 基准列
     */
    mergeTableRowSpan(props, datumKey) {
      const data = this.tableData;
      let spanArr = [];
      const _this = this;
      let resArr = [];
      props.forEach(prop => {
        let key = "";
        let ind = null;
        // 获取前一列prop
        datumKey = datumKey ?? this.tableOption[0].prop;
        const columKeys = this.tableOption.map(item => item.prop);

        columKeys.forEach((ev, index) => {
          if (ev === prop) {
            ind = index;
            return false;
          } else {
            key = ev;
          }
        });
        resArr = _this.merge(data, ind, prop, datumKey, spanArr);
      });
      if (this.expand) {
        resArr.unshift([]);
      }
      if (this.selection) {
        resArr.unshift([]);
      }
      return resArr;
    },
    /**
     *
     * @param {*} idx 当前列的索引
     * @param {*} prop 当前合并列的属性
     * @param {*} datumKey 基准列
     * @param {*} spanArr 结果集合
     */
    merge(data, idx, prop, datumKey, spanArr) {
      const that = this;
      spanArr[idx] = []; // 存储要合并的数组
      let position = 0; // 存储要合并的位置
      data.forEach((item, index) => {
        if (index === 0) {
          spanArr[idx].push(1);
          position = 0;
        } else {
          if (
            data[index][prop] === data[index - 1][prop] &&
            data[index - 1][datumKey] === data[index][datumKey]
          ) {
            spanArr[idx][position] += 1; // 有相同项
            spanArr[idx].push(0); // 名称相同后往数组里面加一项0
          } else {
            spanArr[idx].push(1); // 同列的前后两行单元格不相同
            position = index;
          }
        }
      });
      return spanArr;
    }
  }
};
</script>
<style scoped lang='scss'>
::v-deep .el-table__empty-text {
  opacity: 0;
}
::v-deep .el-table__empty-text_custom {
  line-height: 60px;
  position: absolute;
  left: 50%;
  bottom: 6px;
  transform: translate(-50%, 0);
  color: #999;
}
.pagination-container {
  background: #fff;
  padding: 32px 16px;
  margin: 0;
}

.pagination-container.hidden {
  display: none;
}
</style>